package com.bijava.files.controller;

import com.bijava.files.configure.FileProperties;
import com.bijava.files.model.ApiEntity;
import com.bijava.files.model.FileData;
import com.bijava.files.utils.FileUtils;
import net.coobird.thumbnailator.Thumbnails;
import org.apache.tika.Tika;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;
import springfox.documentation.annotations.ApiIgnore;

import javax.servlet.http.HttpServletResponse;
import java.io.File;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
import java.util.*;

@CrossOrigin
@Controller
@ApiIgnore
public class FileController {
    @Autowired
    private FileProperties properties;

    /**
     * 跳转到首页
     * @return
     */
    @GetMapping({"/", "/index"})
    public String index() {
        return "index.html";
    }

    /**
     * 上传文件
     */
    @ResponseBody
    @PostMapping("/file/upload")
    public ApiEntity<FileData> upload(@RequestParam MultipartFile file) {
        //保存文件的根路径
        String root = properties.getRoot();
        //上传文件时是否重命名
        Boolean uuidName = properties.getUuidName();
        //是否使用缩略图
        Boolean useSm = properties.getUseSm();

        //文件原始名称
        String originalFileName = file.getOriginalFilename();
        //最后一个点的下标位置
        int lastSpotIndex = originalFileName.lastIndexOf(".");
        //文件前缀名称
        String prefix = originalFileName.substring(0, lastSpotIndex);
        //文件后缀名称
        String suffix = originalFileName.substring(lastSpotIndex + 1);

        String path;
        File outFile;
        //根据当前日期创建文件夹路径
        String dateFolder  = FileUtils.getDate();
        if (uuidName != null && uuidName) {
            //开启重命名后，通过uuid生成名称
            path = dateFolder + FileUtils.getUUID() + "." + suffix;
            outFile = new File(File.listRoots()[0], root + path);
        } else {
            //未开启重命名，则检查是否存在重名的文件，有则添加(1)(2)等后缀
            int index = 1;
            path = dateFolder + originalFileName;
            outFile = new File(File.listRoots()[0], root + path);
            while (outFile.exists()) {
                path = dateFolder + prefix + "(" + index + ")." + suffix;
                outFile = new File(File.listRoots()[0], root + path);
                index++;
            }
        }

        try {
            //检查目标文件夹是否存在，不存在就创建
            if (!outFile.getParentFile().exists()) {
                outFile.getParentFile().mkdirs();
            }
            //将文件保存到目标文件夹
            file.transferTo(outFile);

            FileData fileData = new FileData(path);

            //是否需要生成缩略图
            if (useSm != null && useSm) {
                // 获取文件类型
                String contentType = new Tika().detect(outFile);
                //文件类型是图片则添加缩略图
                if (contentType != null && contentType.startsWith("image/")) {
                    File smImg = new File(File.listRoots()[0], root + "sm/" + path);
                    if (!smImg.getParentFile().exists()) {
                        smImg.getParentFile().mkdirs();
                    }
                    Thumbnails.of(outFile).scale(1f).outputQuality(0.25f).toFile(smImg);

                    fileData.setSmUrl("sm/" + path);
                }
            }

            return ApiEntity.success("上传成功",fileData);
        } catch (Exception e) {
            e.printStackTrace();
            return ApiEntity.error(e.getMessage());
        }
    }

    /**
     * 查看原文件
     */
    @GetMapping("/file/{year}/{month}/{day}/{file:.+}")
    public String file(@PathVariable("year") String year, @PathVariable("month") String month,
                       @PathVariable("day") String day, @PathVariable("file") String fileName, HttpServletResponse response) {
        String root = properties.getRoot();
        Boolean useNginx = properties.getUseNginx();
        String nginxUrl = properties.getNginxUrl();

        String filePath = year + "/" + month + "/" + day + "/" + fileName;
        if (useNginx) {
            if (nginxUrl == null) {
                nginxUrl = "/";
            }
            if (!nginxUrl.endsWith("/")) {
                nginxUrl += "/";
            }
            String newName;
            try {
                newName = URLEncoder.encode(filePath, "utf-8");
            } catch (UnsupportedEncodingException e) {
                e.printStackTrace();
                newName = filePath;
            }
            return "redirect:" + nginxUrl + newName;
        }
        if (root == null) {
            root = "/";
        }
        if (!root.endsWith("/")) {
            root += "/";
        }
        FileUtils.outputFile(root + filePath, response);
        return null;
    }

    /**
     * 查看缩略图
     */
    @GetMapping("/file/sm/{year}/{month}/{day}/{file:.+}")
    public String fileSm(@PathVariable("year") String year, @PathVariable("month") String month,
                         @PathVariable("day") String day, @PathVariable("file") String fileName, HttpServletResponse response) {
        String root = properties.getRoot();
        Boolean useNginx = properties.getUseNginx();
        String nginxUrl = properties.getNginxUrl();
        String filePath = "sm/" + year + "/" + month + "/" + day + "/" + fileName;
        if (useNginx) {
            if (nginxUrl == null) {
                nginxUrl = "/";
            }
            if (!nginxUrl.endsWith("/")) {
                nginxUrl += "/";
            }
            String newName;
            try {
                newName = URLEncoder.encode(filePath, "utf-8");
            } catch (UnsupportedEncodingException e) {
                e.printStackTrace();
                newName = filePath;
            }
            return "redirect:" + nginxUrl + newName;
        }
        if (root == null) {
            root = "/";
        }
        if (!root.endsWith("/")) {
            root += "/";
        }
        FileUtils.outputFile(root + filePath, response);
        return null;
    }

    /**
     * 获取全部文件
     */
    @ResponseBody
    @GetMapping("/file/list")
    public ApiEntity list(String dir, String accept, String exts) {
        String root = properties.getRoot();
        String[] mExts = null;
        if (exts != null && !exts.trim().isEmpty()) {
            mExts = exts.split(",");
        }
        if (root == null) {
            root = "/";
        }
        if (!root.endsWith("/")) {
            root += "/";
        }

        if (dir == null || "/".equals(dir)) {
            dir = "";
        } else if (dir.startsWith("/")) {
            dir = dir.substring(1);
        }
        File file = new File(File.listRoots()[0], root + dir);
        File[] listFiles = file.listFiles();
        List<Map> dataList = new ArrayList<>();
        if (listFiles != null) {
            for (File f : listFiles) {
                if ("sm".equals(f.getName())) {
                    continue;
                }
                Map<String, Object> fileMap = new HashMap<>();
                //文件名称
                fileMap.put("name", f.getName());
                //修改时间
                fileMap.put("updateTime", f.lastModified());
                //是否是目录
                fileMap.put("isDir", f.isDirectory());
                if (f.isDirectory()) {
                    //文件类型
                    fileMap.put("type", "dir");
                } else {
                    //文件地址
                    fileMap.put("url", (dir.isEmpty() ? dir : (dir + "/")) + f.getName());

                    String suffix = f.getName().substring(f.getName().lastIndexOf(".") + 1);
                    try {
                        //Path path = Paths.get(f.getName());
                        //contentType = Files.probeContentType(path);

                        //获取文件类型
                        String contentType = new Tika().detect(f);
                        // 筛选文件类型
                        if (accept != null && !accept.trim().isEmpty() && !accept.equals("file")) {
                            if (contentType == null || !contentType.startsWith(accept + "/")) {
                                continue;
                            }
                            if (mExts != null) {
                                for (String ext : mExts) {
                                    if (!f.getName().endsWith("." + ext)) {
                                        continue;
                                    }
                                }
                            }
                        }
                        // 获取文件图标
                        String type = FileUtils.checkFileType(suffix,contentType);
                        fileMap.put("type", type);
                        // 是否有缩略图
                        String smUrl = "sm/" + (dir.isEmpty() ? dir : (dir + "/")) + f.getName();
                        if (new File(File.listRoots()[0], root + smUrl).exists()) {
                            //缩略图地址
                            fileMap.put("hasSm", true);
                            fileMap.put("smUrl", smUrl);
                        }
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                }
                dataList.add(fileMap);
            }
        }
        // 根据上传时间排序
        Collections.sort(dataList, (o1, o2) -> {
            Long l1 = (long) o1.get("updateTime");
            Long l2 = (long) o2.get("updateTime");
            return l1.compareTo(l2);
        });
        // 把文件夹排在前面
        Collections.sort(dataList, (o1, o2) -> {
            Boolean l1 = (boolean) o1.get("isDir");
            Boolean l2 = (boolean) o2.get("isDir");
            return l2.compareTo(l1);
        });

        return ApiEntity.success("查询成功",dataList);
    }

    /**
     * 删除
     */
    @ResponseBody
    @RequestMapping("/file/del")
    public ApiEntity del(String file) {
        String root = properties.getRoot();
        if (root == null) {
            root = "/";
        }
        if (!root.endsWith("/")) {
            root += "/";
        }
        if (file != null && !file.isEmpty()) {
            File f = new File(File.listRoots()[0], root + file);
            if (f.delete()) {
                File smF = new File(File.listRoots()[0], root + "sm/" + file);
                smF.delete();
                return ApiEntity.success("删除成功");
            }
        }
        return ApiEntity.error("删除失败");
    }
}